import { Inject, Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as Client from 'ali-oss';
import * as dayjs from 'dayjs';

// 参考文档：https://developer.aliyun.com/article/1320648

@Injectable()
export class OssService {
  @Inject(ConfigService)
  private readonly config: ConfigService;

  // 获取签名
  async getSignature() {
    const OssConfig = {
      region: this.config.get('oss.region'),
      accessKeyId: this.config.get('oss.accessKeyId'),
      accessKeySecret: this.config.get('oss.accessKeySecret'),
      bucket: this.config.get('oss.bucket'),
      // 由于回调地址必须是外网地址，所以这里暂时注释掉
      // callbackUrl: this.config.get('oss.callbackUrl'), // 配置回调，让 OSS 调用它并传递参数过来
    };

    // 创建 OSS 客户端
    const client = new Client(OssConfig);

    // 定义签名的有效期：为 1 天
    const date = new Date();
    date.setDate(date.getDate() + 1);

    // 定义签名传递的参数
    const policy = {
      expiration: date.toISOString(), // 设置该 Policy 的失效时间
      conditions: [
        ['content-length-range', 0, 1048576000], // 设置上传文件的大小限制: 0B ~ 1GB
      ],
    };

    // 计算签名
    const formData = await client.calculatePostSignature(policy);

    // 生成 bucket 域名，客户端将向此地址发送请求
    const location = await client.getBucketLocation();
    const host = `https://${OssConfig.bucket}.${location.location}.aliyuncs.com`;

    console.log(formData);

    // const callback = {
    //   // 设置回调请求的服务器地址
    //   callbackUrl: this.config.get('oss.callbackUrl'),
    //   // 设置回调的内容，${object} 等占位符会由 OSS 进行填充
    //   // ${object}表示文件的存储路径，${mimeType}表示资源类型，对于图片类型的文件，可以通过${imageInfo.height}等去设置宽高信息
    //   callbackBody:
    //     'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
    //   // 设置回调的内容类型，也支持 application/json
    //   callbackBodyType: 'application/x-www-form-urlencoded',
    // };

    // 响应给客户端的签名信息和策略等信息
    return {
      expire: dayjs().add(1, 'day').unix().toString(),
      policy: formData.policy,
      signature: formData.Signature,
      accessId: formData.OSSAccessKeyId,
      host,
      dir: this.config.get('oss.dir'),
      // 传给客户端的回调参数，需要通过Buffer.from 对 JSON 进行 Base64 编码
      // callback: Buffer.from(JSON.stringify(callback)).toString('base64'),
    };
  }

  // 回调就是调用这个接口，oss服务器会向这个接口发送请求，然后再将响应结果返回给oss服务器
  async getResult(xOssPubKeyUrl: string, file: any) {
    // 通过 Base64 解码公钥地址
    const pubKeyAddr = Buffer.from(xOssPubKeyUrl, 'base64').toString('ascii');

    //  判断请求头中的 x-oss-pub-key-url 是否来源于OSS服务器
    if (!pubKeyAddr.startsWith('https://gosspublic.alicdn.com/')) {
      return {
        status: 'verify not ok',
      };
    }

    // 如果 x-oss-pub-key-url 来源于OSS服务器，则返回“Ok”和文件信息，表明回调成功
    return {
      file,
      status: 'Ok',
    };
  }
}

// 参考文档：
// https://developer.aliyun.com/article/1320648
// https://developer.aliyun.com/article/1321127

// 总体思路：
// 1. 客户端上传文件前，先调用 getSignature 函数获取临时签名，拿到后端返回签名信息数据
// 2. 服务器生成临时签名（39行），并设置回调请求地址（47行）
// 3. 客户端拿到签名，回调请求地址等信息后，将文件上传后 OSS
// 4. OSS 完成文件处理后，按照回调地址将结果发送给服务器（就是调用 getResult 函数)
// 5. 服务器处理完成后，将结果响应给 OSS
// 6. OSS 将结果返回给客户端

// 客户端职责
// 1. 调用 getSignature 函数获取签名信息
// 2. 将签名信息和文件信息传递给 OSS （通过formdata + post）
// axios({
//     method: "post",
//     url: host,
//     data: formData,
//     headers: {
//       "Content-Type": "multipart/form-data",
//     },
//   });
// 3. OSS 完成文件处理后，将结果返回给客户端

// 服务器职责
// 1. 生成签名信息，将签名信息返回给客户端
// 2. 处理 OSS 回调请求，将结果响应给 OSS

// OSS 职责
// 1. 接收客户端上传的文件
// 2. 调用 getResult 函数进行处理，将结果返回 OSS
// 2. 将结果返回给客户端
